package org.zjt.zero_copy.byte_buffer;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Scanner;

/**
 * Description:
 *
 * @author juntao.zhang
 * Date: 2018-05-30 上午11:27
 * <p>
 * <p>
 * <p>
 * 通过mmap实现的零拷贝I/O
 * mmap(内存映射)是一个比sendfile昂贵但优于传统I/O的方法。
 */
@Slf4j
public class Main {

    private static final String DELIMITER = " ";


    private static final String FILE_PATH = "/Users/juntao.zhang/dev/workspace/myproject/java-basic/src/main/java/org/zjt/zero_copy/byte_buffer/Main.java";

    public static void main(String[] args) throws IOException {

        // 堆 内存
        ByteBuffer allocate = ByteBuffer.allocate(30);
        allocate.put("hello world".getBytes());
        allocate.putChar('S');
        allocate.flip();
        System.out.println("before get():" + allocate);
        System.out.println((char) allocate.get());
        System.out.println((char) allocate.getChar(11));
        System.out.println("after get():" + allocate);


        allocate.rewind();
        allocate.putChar('X');
        allocate.flip();
        System.out.println((char) allocate.getChar());

        //  超出内容，会跑出异常： java.nio.BufferUnderflowException
        System.out.println(allocate.getChar());




        //直接内存
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(30);
        byteBuffer.putChar('W');
        byteBuffer.flip();
        System.out.println(byteBuffer.getChar());




    }


    /**
     *
     * MappedByteBuffer 与DirectByteBuffer类似，这也是JVM堆外部的情况。
     *
     * @throws IOException
     */
    public static void mappedByteBufferTest() throws IOException {

        // 创建文件 mapped
        File file = new File(FILE_PATH);
        long len = file.length();

        FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel();
        byte[] ds = new byte[(int) len];
        MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, len);

        // 读取mapped中的信息,按照 byte 读取
        for (int offset = 0; offset < len; offset++) {
            byte b = mappedByteBuffer.get();
            ds[offset] = b;
        }

        // 利用Scanner 对数据流进行输出，并用 useDelimiter(" ") 来分割输出，为迭代器。
        Scanner scanner = new Scanner(new ByteArrayInputStream(ds)).useDelimiter(DELIMITER);
        while (scanner.hasNext()) {
            System.out.print(scanner.next() + DELIMITER);
        }
    }
}
